﻿using System;
using System.Collections.Generic;
using System.ComponentModel;

using D2D = Microsoft.WindowsAPICodePack.DirectX.Direct2D1;
using DI = Microsoft.WindowsAPICodePack.DirectX.WindowsImagingComponent;
using DW = Microsoft.WindowsAPICodePack.DirectX.DirectWrite;
using Paint = System.Drawing;

namespace Framework
{
    public class Pen : Base
    {
        public double DashArray;
        public PenLineCap DashCap;
        public double DashOffset;
        public PenLineCap EndLineCap;
        public PenLineJoin LineJoin;
        public double MiterLimit;
        public PenLineCap StartLineCap;
        public double Thickness;
        public Brush Brush;
    }

    public abstract class Brush : Base
    {
        static Brush()
        {
            RegisterType(typeof(Brush));
            RegisterProp(typeof(Timeline), "Opacity", typeof(double), null);
            RegisterProp(typeof(Timeline), "Transform", typeof(Transform), null);
            RegisterProp(typeof(Timeline), "RelativeTransform", typeof(Transform), null);                       
        }

        public double Opacity { get; set; }
        public Transform Transform { get; set; }
        public Transform RelativeTransform { get; set; }

        public D2D.Brush D2DBrush = null;
        public abstract D2D.Brush GetD2D();
    }
    
    public enum BrushMappingMode
    {
        Absolute,
        RelativeToBoundingBox,
    }

    public enum ColorInterpolationMode
    {
        ScRgbLinearInterpolation,
        SRgbLinearInterpolation,
    }

    public sealed class GradientStop : Base
    {
        static GradientStop()
        {
            RegisterType(typeof(GradientStop));
            RegisterProp(typeof(GradientStop), "Color", typeof(Color), null);
            RegisterProp(typeof(GradientStop), "Offset", typeof(Double), null);
        }

        public Color Color;
        public double Offset;
    }

    public class GradientStopCollection : Collection<GradientStop>
    {
    }
    
    public abstract class GradientBrush : Brush
    {
        static GradientBrush()
        {
            RegisterType(typeof(GradientBrush), typeof(Brush));
            RegisterProp(typeof(GradientBrush), "SpreadMethod", typeof(GradientSpreadMethod), null);
            RegisterProp(typeof(GradientBrush), "MappingMode", typeof(BrushMappingMode), null);
            RegisterProp(typeof(GradientBrush), "ColorInterpolationMode", typeof(ColorInterpolationMode), null);
            RegisterProp(typeof(GradientBrush), "GradientStops", typeof(GradientStopCollection), null);
        }

        public GradientSpreadMethod SpreadMethod;
        public BrushMappingMode MappingMode;
        public ColorInterpolationMode ColorInterpolationMode;
        public GradientStopCollection GradientStops = new GradientStopCollection();
    
    }

    public abstract class TileBrush : Brush
    {
        static TileBrush()
        {
            RegisterType(typeof (TileBrush), typeof (Brush));
            RegisterProp(typeof(TileBrush), "AlignmentX", typeof(AlignmentX), null);
            RegisterProp(typeof(TileBrush), "AlignmentY", typeof(AlignmentY), null);
            RegisterProp(typeof(TileBrush), "Stretch", typeof(Stretch), null);
        }
    }

    public enum GradientSpreadMethod
    {
        Pad,
        Reflect,
        Repeat,
    }
    
    public sealed class ImageBrush : TileBrush
    {
        static ImageBrush()
        {
            RegisterType(typeof(ImageBrush), typeof(TileBrush));
            RegisterProp(typeof(ImageBrush), "ImageSource", typeof(BitmapImage), null);
        }

        public string ImageSource { get; set; }

        public override D2D.Brush GetD2D()
        {
            DI.BitmapDecoder decoder = Window.current.imagingFactory.CreateDecoderFromFileName(ImageSource, DI.DesiredAccess.Read, DI.DecodeMetadataCacheOption.OnLoad);
            DI.BitmapFrameDecode source = decoder.GetFrame(0);
            DI.FormatConverter converter = Window.current.imagingFactory.CreateFormatConverter();
            converter.Initialize(
                source.ToBitmapSource(),
                DI.PixelFormats.Pbgra32Bpp,
                DI.BitmapDitherType.None,
                DI.BitmapPaletteType.MedianCut
                );
            D2D.D2DBitmap bitmap = Window.current.renderTarget.CreateBitmapFromWicBitmap(converter.ToBitmapSource());
            return Window.current.renderTarget.CreateBitmapBrush(bitmap);
        }
    }

    public sealed class LinearGradientBrush : GradientBrush
    {
        static LinearGradientBrush()
        {
            RegisterType(typeof(LinearGradientBrush), typeof(GradientBrush));
            RegisterProp(typeof(LinearGradientBrush), "StartPoint", typeof(Point), null);
            RegisterProp(typeof(LinearGradientBrush), "EndPoint", typeof(Point), null);
        }

        public Point StartPoint { get; set; }
        public Point EndPoint { get; set; }

        public override D2D.Brush GetD2D()
        {
            List<D2D.GradientStop> stops = new List<D2D.GradientStop>();
            foreach (var i in GradientStops)
            {
                stops.Add(new D2D.GradientStop((float)i.Offset, i.Color.GetD2D()));
            }

            return Window.current.renderTarget.CreateLinearGradientBrush(
                new D2D.LinearGradientBrushProperties() { StartPoint = StartPoint.GetD2D(), EndPoint = EndPoint.GetD2D() },
                    Window.current.renderTarget.CreateGradientStopCollection(
                        stops, D2D.Gamma.Linear, D2D.ExtendMode.Clamp));

        }
    }

    public sealed class RadialGradientBrush : GradientBrush
    {
        static RadialGradientBrush()
        {
            RegisterType(typeof (RadialGradientBrush), typeof (GradientBrush));
            RegisterProp(typeof(RadialGradientBrush), "Center", typeof(Point), null);
            RegisterProp(typeof(RadialGradientBrush), "GradientOrigin", typeof(Point), null);
            RegisterProp(typeof(RadialGradientBrush), "RadiusX", typeof(double), null);
            RegisterProp(typeof(RadialGradientBrush), "RadiusY", typeof(double), null);
        }

        public Point StartPoint { get; set; }
        public Point EndPoint { get; set; }

        public override D2D.Brush GetD2D()
        {
            List<D2D.GradientStop> stops = new List<D2D.GradientStop>();
            foreach (var i in GradientStops)
            {
                stops.Add(new D2D.GradientStop((float)i.Offset, i.Color.GetD2D()));
            }

            return Window.current.renderTarget.CreateLinearGradientBrush(
                new D2D.LinearGradientBrushProperties() { StartPoint = StartPoint.GetD2D(), EndPoint = EndPoint.GetD2D() },
                    Window.current.renderTarget.CreateGradientStopCollection(
                        stops, D2D.Gamma.Linear, D2D.ExtendMode.Clamp));

        }
    }

    public sealed class SolidColorBrush : Brush
    {
        static SolidColorBrush()
        {
            RegisterType(typeof(SolidColorBrush), typeof(Brush));
            RegisterProp(typeof(SolidColorBrush), "Color", typeof(Color), null);
        }

        public Color Color;

        public override D2D.Brush GetD2D()
        {
            return Window.current.renderTarget.CreateSolidColorBrush(Color.GetD2D());
        }

        public SolidColorBrush()
        { }

        public SolidColorBrush(Color color)
        {
            Color = color;
        }
    }

    public enum PenLineCap
    {
        Flat,
        Square,
        Round,
        Triangle
    }

    public enum PenLineJoin
    {
        Miter,
        Bevel,
        Round
    }
}
